home *** CD-ROM | disk | FTP | other *** search
/ InterCD 2000 September / september_2000.iso / intercd / root / ^Linux / WindowMaker / src / appicon.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-03-29  |  25.0 KB  |  936 lines

  1. /* appicon.c- icon for applications (not mini-window)
  2.  *
  3.  *  Window Maker window manager
  4.  *
  5.  *  Copyright (c) 1997, 1998 Alfredo K. Kojima
  6.  *  Copyright (c) 1998       Dan Pascu
  7.  *
  8.  *  This program is free software; you can redistribute it and/or modify
  9.  *  it under the terms of the GNU General Public License as published by
  10.  *  the Free Software Foundation; either version 2 of the License, or
  11.  *  (at your option) any later version.
  12.  *
  13.  *  This program is distributed in the hope that it will be useful,
  14.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16.  *  GNU General Public License for more details.
  17.  *
  18.  *  You should have received a copy of the GNU General Public License
  19.  *  along with this program; if not, write to the Free Software
  20.  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
  21.  *  USA.
  22.  */
  23.  
  24. #include "wconfig.h"
  25.  
  26. #include <X11/Xlib.h>
  27. #include <X11/Xutil.h>
  28. #include <stdlib.h>
  29. #include <string.h>
  30.  
  31. #include "WindowMaker.h"
  32. #include "wcore.h"
  33. #include "window.h"
  34. #include "icon.h"
  35. #include "appicon.h"
  36. #include "actions.h"
  37. #include "stacking.h"
  38. #include "dock.h"
  39. #include "funcs.h"
  40. #include "defaults.h"
  41. #include "workspace.h"
  42. #include "superfluous.h"
  43. #include "menu.h"
  44. #include "framewin.h"
  45. #include "dialog.h"
  46. #include "client.h"
  47. #ifdef XDND
  48. #include "xdnd.h"
  49. #endif
  50. #include "wmsound.h"
  51. #include "WINGsP.h"
  52.  
  53.  
  54. /*
  55.  * icon_file for the dock is got from the preferences file by
  56.  * using the classname/instancename
  57.  */
  58.  
  59. /**** Global variables ****/
  60. extern Cursor wCursor[WCUR_LAST];
  61. extern WPreferences wPreferences;
  62.  
  63. #define MOD_MASK       wPreferences.modifier_mask
  64.  
  65. void appIconMouseDown(WObjDescriptor *desc, XEvent *event);
  66. static void iconDblClick(WObjDescriptor *desc, XEvent *event);
  67. static void iconExpose(WObjDescriptor *desc, XEvent *event);
  68.  
  69.  
  70.  
  71. WAppIcon*
  72. wAppIconCreateForDock(WScreen *scr, char *command, char *wm_instance,
  73.               char *wm_class, int tile)
  74. {
  75.     WAppIcon *dicon;
  76.     char *path;
  77.  
  78.     dicon = wmalloc(sizeof(WAppIcon));
  79.     wretain(dicon);
  80.     memset(dicon, 0, sizeof(WAppIcon));
  81.     dicon->yindex = -1;
  82.     dicon->xindex = -1;
  83.  
  84.     dicon->prev = NULL;
  85.     dicon->next = scr->app_icon_list;
  86.     if (scr->app_icon_list) {
  87.         scr->app_icon_list->prev = dicon;
  88.     }
  89.     scr->app_icon_list = dicon;
  90.  
  91.     if (command) {
  92.     dicon->command = wstrdup(command);
  93.     }
  94.     if (wm_class)
  95.       dicon->wm_class = wstrdup(wm_class);
  96.     if (wm_instance)
  97.       dicon->wm_instance = wstrdup(wm_instance);
  98.  
  99.     path = wDefaultGetIconFile(scr, wm_instance, wm_class, True);
  100.     if (!path && command) {
  101.     wApplicationExtractDirPackIcon(scr, command, wm_instance, wm_class);
  102.  
  103.     path = wDefaultGetIconFile(scr, wm_instance, wm_class, False);
  104.     }
  105.  
  106.     if (path)
  107.     path = FindImage(wPreferences.icon_path, path);
  108.  
  109.     dicon->icon = wIconCreateWithIconFile(scr, path, tile);
  110.     if (path)
  111.     free(path);
  112. #ifdef XDND
  113.     wXDNDMakeAwareness(dicon->icon->core->window);
  114. #endif
  115. #ifdef REDUCE_APPICONS
  116.     dicon->num_apps = 0;
  117. #endif
  118. #ifdef DEMATERIALIZE_ICON
  119.     {
  120.         XSetWindowAttributes attribs;
  121.         attribs.save_under = True;
  122.         XChangeWindowAttributes(dpy, dicon->icon->core->window,
  123.                 CWSaveUnder, &attribs);
  124.     }
  125. #endif
  126.  
  127.     /* will be overriden by dock */
  128.     dicon->icon->core->descriptor.handle_mousedown = appIconMouseDown;
  129.     dicon->icon->core->descriptor.handle_expose = iconExpose;
  130.     dicon->icon->core->descriptor.parent_type = WCLASS_APPICON;
  131.     dicon->icon->core->descriptor.parent = dicon;
  132.     AddToStackList(dicon->icon->core);
  133.  
  134.     return dicon;
  135. }
  136.  
  137.  
  138.  
  139. WAppIcon*
  140. wAppIconCreate(WWindow *leader_win)
  141. {
  142.     WAppIcon *aicon;
  143. #ifdef REDUCE_APPICONS
  144.     WAppIcon *atmp;
  145.     WAppIconAppList *applist;
  146.     char *tinstance, *tclass;
  147. #endif
  148.     WScreen *scr = leader_win->screen_ptr;
  149.  
  150.     aicon = wmalloc(sizeof(WAppIcon));
  151.     wretain(aicon);
  152.     memset(aicon, 0, sizeof(WAppIcon));
  153. #ifdef REDUCE_APPICONS
  154.     applist = wmalloc(sizeof(WAppIconAppList));
  155.     memset(applist, 0, sizeof(WAppIconAppList));
  156.     applist->wapp = wApplicationOf(leader_win->main_window);
  157.     aicon->applist = applist;
  158.     if (applist->wapp == NULL) {
  159.     /* Something's wrong. wApplicationOf() should always return a
  160.      * valid structure.  Rather than violate assumptions, bail. -cls
  161.      */
  162.     free(applist);
  163.     wrelease(aicon);
  164.     return NULL;
  165.     }
  166. #endif
  167.  
  168.     aicon->yindex = -1;
  169.     aicon->xindex = -1;
  170.  
  171.     aicon->prev = NULL;
  172.     aicon->next = scr->app_icon_list;
  173.     if (scr->app_icon_list) {
  174. #ifndef REDUCE_APPICONS
  175.         scr->app_icon_list->prev = aicon;
  176. #else
  177.     /* If we aren't going to have a match, jump straight to new appicon */
  178.     if (leader_win->wm_class == NULL || leader_win->wm_class == NULL)
  179.         atmp = NULL;
  180.     else
  181.     atmp = scr->app_icon_list;
  182.  
  183.     while (atmp != NULL) {
  184.         if ((tinstance = atmp->wm_instance) == NULL)
  185.         tinstance = "";
  186.         if ((tclass = atmp->wm_class) == NULL)
  187.         tclass = "";
  188.         if ((strcmp(leader_win->wm_class, tclass) == 0) &&
  189.         (strcmp(leader_win->wm_instance, tinstance) == 0))
  190.         {
  191.         /* We have a winner */
  192.         wrelease(aicon);
  193.         atmp->num_apps++;
  194.         applist->next = atmp->applist;
  195.         if (atmp->applist)
  196.             atmp->applist->prev = applist;
  197.         atmp->applist = applist;
  198.  
  199.         if (atmp->docked) {
  200.             wDockSimulateLaunch(atmp->dock, atmp);
  201.         }
  202.  
  203.         return atmp;
  204.         }
  205.         atmp = atmp->next;
  206.     }
  207.     if (atmp == NULL) {
  208.         scr->app_icon_list->prev = aicon;
  209.     }
  210. #endif /* REDUCE_APPICONS */
  211.     }
  212.     scr->app_icon_list = aicon;
  213.  
  214.     if (leader_win->wm_class)
  215.         aicon->wm_class = wstrdup(leader_win->wm_class);
  216.     if (leader_win->wm_instance)
  217.         aicon->wm_instance = wstrdup(leader_win->wm_instance);
  218. #ifdef REDUCE_APPICONS
  219.     aicon->num_apps = 1;
  220. #endif
  221.  
  222.     aicon->icon = wIconCreate(leader_win);
  223. #ifdef DEMATERIALIZE_ICON
  224.     {
  225.         XSetWindowAttributes attribs;
  226.         attribs.save_under = True;
  227.         XChangeWindowAttributes(dpy, aicon->icon->core->window,
  228.                 CWSaveUnder, &attribs);
  229.     }
  230. #endif
  231. #ifdef XDND
  232.     wXDNDMakeAwareness(aicon->icon->core->window);
  233. #endif
  234.  
  235.     /* will be overriden if docked */
  236.     aicon->icon->core->descriptor.handle_mousedown = appIconMouseDown;
  237.     aicon->icon->core->descriptor.handle_expose = iconExpose;
  238.     aicon->icon->core->descriptor.parent_type = WCLASS_APPICON;
  239.     aicon->icon->core->descriptor.parent = aicon;
  240.     AddToStackList(aicon->icon->core);
  241.     aicon->icon->show_title = 0;
  242.     wIconUpdate(aicon->icon);
  243.  
  244.     return aicon;
  245. }
  246.  
  247.  
  248. void
  249. wAppIconDestroy(WAppIcon *aicon)
  250. {
  251.     WScreen *scr = aicon->icon->core->screen_ptr;
  252. #ifdef REDUCE_APPICONS
  253.     WAppIconAppList *aptmp;
  254. #endif
  255.  
  256.     RemoveFromStackList(aicon->icon->core);
  257.     wIconDestroy(aicon->icon);
  258.     if (aicon->command)
  259.     free(aicon->command);
  260. #ifdef OFFIX_DND
  261.     if (aicon->dnd_command)
  262.     free(aicon->dnd_command);
  263. #endif
  264.     if (aicon->wm_instance)
  265.       free(aicon->wm_instance);
  266.     if (aicon->wm_class)
  267.       free(aicon->wm_class);
  268. #ifdef REDUCE_APPICONS
  269.     /* There should never be a list but just in case */
  270.     if (aicon->applist != NULL) {
  271.     aptmp = aicon->applist;
  272.         while (aptmp->next) {
  273.         aptmp = aptmp->next;
  274.         free(aptmp->prev);
  275.     }
  276.     free(aptmp);
  277.     }
  278. #endif
  279.  
  280.     if (aicon == scr->app_icon_list) {
  281.         if (aicon->next)
  282.             aicon->next->prev = NULL;
  283.         scr->app_icon_list = aicon->next;
  284.     }
  285.     else {
  286.         if (aicon->next)
  287.             aicon->next->prev = aicon->prev;
  288.         if (aicon->prev)
  289.             aicon->prev->next = aicon->next;
  290.     }
  291.  
  292.     aicon->destroyed = 1;
  293.     wrelease(aicon);
  294. }
  295.  
  296.  
  297.  
  298. #ifdef NEWAPPICON
  299. static void
  300. drawCorner(WIcon *icon, WWindow *wwin, int active)
  301. {
  302.     WScreen *scr = wwin->screen_ptr;
  303.     XPoint points[3];
  304.     GC gc;
  305.  
  306.     points[0].x = 2;
  307.     points[0].y = 2;
  308.     points[1].x = 12;
  309.     points[1].y = 2;
  310.     points[2].x = 2;
  311.     points[2].y = 12;
  312.     if (active) {
  313.     gc=scr->focused_texture->any.gc;
  314.     } else {
  315.     gc=scr->unfocused_texture->any.gc;
  316.     }
  317.     XFillPolygon(dpy, icon->core->window, gc, points, 3,
  318.          Convex, CoordModeOrigin);
  319. }
  320. #endif /* NEWAPPICON */
  321.  
  322.  
  323. static void
  324. drawCorner(WIcon *icon)
  325. {
  326.     WScreen *scr = icon->core->screen_ptr;
  327.     XPoint points[3];
  328.  
  329.     points[0].x = 1;
  330.     points[0].y = 1;
  331.     points[1].x = 12;
  332.     points[1].y = 1;
  333.     points[2].x = 1;
  334.     points[2].y = 12;
  335.     XFillPolygon(dpy, icon->core->window, scr->icon_title_texture->normal_gc,
  336.                  points, 3, Convex, CoordModeOrigin);
  337.     XDrawLine(dpy, icon->core->window, scr->icon_title_texture->light_gc,
  338.               0, 0, 0, 12);
  339.     XDrawLine(dpy, icon->core->window, scr->icon_title_texture->light_gc,
  340.               0, 0, 12, 0);
  341.     /* drawing the second line gives a weird concave look. -Dan */
  342. #if 0
  343.     XDrawLine(dpy, icon->core->window, scr->icon_title_texture->light_gc,
  344.               1, 1, 1, 11);
  345.     XDrawLine(dpy, icon->core->window, scr->icon_title_texture->light_gc,
  346.               1, 1, 11, 1);
  347. #endif
  348. }
  349.  
  350.  
  351. void
  352. wAppIconMove(WAppIcon *aicon, int x, int y)
  353. {
  354.     XMoveWindow(dpy, aicon->icon->core->window, x, y);
  355.     aicon->x_pos = x;
  356.     aicon->y_pos = y;
  357. }
  358.  
  359.  
  360. #ifdef WS_INDICATOR
  361. static void
  362. updateDockNumbers(WScreen *scr)
  363. {
  364.     int length;
  365.     char *ws_numbers;
  366.     GC numbers_gc;
  367.     XGCValues my_gc_values;
  368.     unsigned long my_v_mask = (GCForeground);
  369.     WAppIcon *dicon = scr->dock->icon_array[0];
  370.     
  371.     my_gc_values.foreground = scr->white_pixel;
  372.     numbers_gc = XCreateGC(dpy, dicon->icon->core->window,
  373.                my_v_mask, &my_gc_values);
  374.  
  375.     ws_numbers = malloc(20);
  376.     sprintf(ws_numbers, "%i [ %i ]", scr->current_workspace+1,
  377.         ((scr->current_workspace/10)+1));
  378.     length = strlen(ws_numbers);
  379.     
  380.     XClearArea(dpy, dicon->icon->core->window, 2, 2, 50,
  381.            WMFontHeight(scr->icon_title_font)+1, False);
  382.     
  383.     XSetForeground(dpy, numbers_gc, scr->black_pixel);
  384.     WMDrawString(scr->wmscreen, dicon->icon->core->window, numbers_gc,
  385.          scr->icon_title_font, 4, 3, ws_numbers, length);
  386.  
  387.     XSetForeground(dpy, numbers_gc, scr->white_pixel);
  388.     WMDrawString(scr->wmscreen, dicon->icon->core->window, numbers_gc,
  389.          scr->icon_title_font, 3, 2, ws_numbers, length);
  390.  
  391.     XFreeGC(dpy, numbers_gc);
  392.     free(ws_numbers);
  393. }
  394. #endif /* WS_INDICATOR */
  395.  
  396.  
  397. void
  398. wAppIconPaint(WAppIcon *aicon)
  399. {
  400.     WScreen *scr = aicon->icon->core->screen_ptr;
  401.  
  402.     wIconPaint(aicon->icon);
  403.  
  404.  
  405. # ifdef WS_INDICATOR
  406.     if (aicon->docked && scr->dock && scr->dock==aicon->dock &&
  407.         aicon->yindex==0)
  408.     updateDockNumbers(scr);
  409. # endif
  410.     if (scr->dock_dots && aicon->docked && !aicon->running
  411.     && aicon->command!=NULL) {
  412.     XSetClipMask(dpy, scr->copy_gc, scr->dock_dots->mask);
  413.     XSetClipOrigin(dpy, scr->copy_gc, 0, 0);
  414.     XCopyArea(dpy, scr->dock_dots->image, aicon->icon->core->window,
  415.           scr->copy_gc, 0, 0, scr->dock_dots->width,
  416.           scr->dock_dots->height, 0, 0);
  417.     }
  418.  
  419. #ifdef HIDDENDOT
  420.     {
  421.         WApplication *wapp;
  422.     wapp = wApplicationOf(aicon->main_window);
  423.     if (wapp && wapp->flags.hidden) {
  424.             XSetClipMask(dpy, scr->copy_gc, scr->dock_dots->mask);
  425.             XSetClipOrigin(dpy, scr->copy_gc, 0, 0);
  426.             XCopyArea(dpy, scr->dock_dots->image,
  427.                       aicon->icon->core->window,
  428.                       scr->copy_gc, 0, 0, 7,
  429.                       scr->dock_dots->height, 0, 0);
  430.         }
  431.     }
  432. #endif /* HIDDENDOT */
  433.  
  434.     if (aicon->omnipresent)
  435.         drawCorner(aicon->icon);
  436.  
  437.     XSetClipMask(dpy, scr->copy_gc, None);
  438.     if (aicon->launching) {
  439.     XFillRectangle(dpy, aicon->icon->core->window, scr->stipple_gc,
  440.                0, 0, wPreferences.icon_size, wPreferences.icon_size);
  441.     }
  442. }
  443.  
  444.  
  445.  
  446. #define canBeDocked(wwin)  ((wwin) && ((wwin)->wm_class||(wwin)->wm_instance))
  447.  
  448. #ifdef REDUCE_APPICONS
  449. unsigned int
  450. wAppIconReduceAppCount(WApplication *wapp)
  451. {
  452.     WAppIconAppList *applist;
  453.  
  454.     if (wapp == NULL)
  455.     return 0;
  456.  
  457.     if (wapp->app_icon == NULL)
  458.     return 0;
  459.  
  460.     /* If given a main window, check the applist
  461.      * and remove the if it exists
  462.      */
  463.     applist = wapp->app_icon->applist;
  464.     while (applist != NULL) {
  465.     if (applist->wapp == wapp) {
  466.         /* If this app owns the appicon, change the appicon's
  467.          * owner to the next app in the list or NULL
  468.          */
  469.         if (wapp->app_icon->icon->owner 
  470.         == applist->wapp->main_window_desc) {
  471.         if (applist->next) {
  472.             wapp->app_icon->icon->owner = applist->next->wapp->main_window_desc;
  473.         } else if (applist->prev) {
  474.             wapp->app_icon->icon->owner = applist->prev->wapp->main_window_desc;
  475.         } else {
  476.             wapp->app_icon->icon->owner = NULL;
  477.         }
  478.         }
  479.         if (applist->prev)
  480.         applist->prev->next = applist->next;
  481.  
  482.         if (applist->next)
  483.         applist->next->prev = applist->prev;
  484.  
  485.         if (applist == wapp->app_icon->applist)
  486.         wapp->app_icon->applist = applist->next;
  487.         
  488.         free(applist);
  489.  
  490.         if (wapp->app_icon->applist != NULL)
  491.         wapp->app_icon->main_window = wapp->app_icon->applist->wapp->main_window;
  492.  
  493.         return (--wapp->app_icon->num_apps);
  494.     }
  495.     applist = applist->next;
  496.     }
  497.     return (--wapp->app_icon->num_apps);
  498. }
  499. #endif
  500.  
  501.  
  502. static void
  503. hideCallback(WMenu *menu, WMenuEntry *entry)
  504. {
  505.     WApplication *wapp = (WApplication*)entry->clientdata;
  506.  
  507.     if (wapp->flags.hidden) {
  508.     wWorkspaceChange(menu->menu->screen_ptr, wapp->last_workspace);
  509.     wUnhideApplication(wapp, False, False);
  510.     } else {
  511.     wHideApplication(wapp);
  512.     }
  513. }
  514.  
  515.  
  516. static void
  517. unhideHereCallback(WMenu *menu, WMenuEntry *entry)
  518. {
  519.     WApplication *wapp = (WApplication*)entry->clientdata;
  520.  
  521.     wUnhideApplication(wapp, False, True);
  522. }
  523.  
  524.  
  525. static void
  526. setIconCallback(WMenu *menu, WMenuEntry *entry)
  527. {
  528.     WAppIcon *icon = ((WApplication*)entry->clientdata)->app_icon;
  529.     char *file=NULL;
  530.     WScreen *scr;
  531.     int result;
  532.  
  533.     assert(icon!=NULL);
  534.  
  535.     if (icon->editing)
  536.     return;
  537.     icon->editing = 1;
  538.     scr = icon->icon->core->screen_ptr;
  539.  
  540.     wretain(icon);
  541.  
  542.     result = wIconChooserDialog(scr, &file, icon->wm_instance, icon->wm_class);
  543.  
  544.     if (result && !icon->destroyed) {
  545.     if (file[0]==0) {
  546.         free(file);
  547.         file = NULL;
  548.     }
  549.     if (!wIconChangeImageFile(icon->icon, file)) {
  550.         wMessageDialog(scr, _("Error"),
  551.                _("Could not open specified icon file"),
  552.                _("OK"), NULL, NULL);
  553.     } else {
  554.         wDefaultChangeIcon(scr, icon->wm_instance, icon->wm_class, file);
  555.         wAppIconPaint(icon);
  556.     }
  557.     if (file)
  558.         free(file);
  559.     }
  560.     icon->editing = 0;
  561.     wrelease(icon);
  562. }
  563.  
  564.  
  565. static void
  566. killCallback(WMenu *menu, WMenuEntry *entry)
  567. {
  568.     WApplication *wapp = (WApplication*)entry->clientdata;
  569.     char *buffer;
  570.  
  571.     if (!WCHECK_STATE(WSTATE_NORMAL))
  572.     return;
  573.  
  574.     WCHANGE_STATE(WSTATE_MODAL);
  575.  
  576.     assert(entry->clientdata!=NULL);
  577.  
  578.     buffer = wstrappend(wapp->app_icon ? wapp->app_icon->wm_class : NULL,
  579.             _(" will be forcibly closed.\n"
  580.               "Any unsaved changes will be lost.\n"
  581.               "Please confirm."));
  582.  
  583.     wretain(wapp->main_window_desc);
  584.     if (wPreferences.dont_confirm_kill
  585.     || wMessageDialog(menu->frame->screen_ptr, _("Kill Application"),
  586.               buffer, _("Yes"), _("No"), NULL)==WAPRDefault) {
  587.     if (!wapp->main_window_desc->flags.destroyed)
  588.         wClientKill(wapp->main_window_desc);
  589.     }
  590.     wrelease(wapp->main_window_desc);
  591.  
  592.     free(buffer);
  593.  
  594.     WCHANGE_STATE(WSTATE_NORMAL);
  595. }
  596.  
  597.  
  598. static WMenu*
  599. createApplicationMenu(WScreen *scr)
  600. {
  601.     WMenu *menu;
  602.  
  603.     menu = wMenuCreate(scr, NULL, False);
  604.     wMenuAddCallback(menu, _("Unhide Here"), unhideHereCallback, NULL);
  605.     wMenuAddCallback(menu, _("Hide"), hideCallback, NULL);
  606.     wMenuAddCallback(menu, _("Set Icon..."), setIconCallback, NULL);
  607.     wMenuAddCallback(menu, _("Kill"), killCallback, NULL);
  608.  
  609.     return menu;
  610. }
  611.  
  612.  
  613. static void
  614. openApplicationMenu(WApplication *wapp, int x, int y)
  615. {
  616.     WMenu *menu;
  617.     WScreen *scr = wapp->main_window_desc->screen_ptr;
  618.     int i;
  619.  
  620.     if (!scr->icon_menu) {
  621.     scr->icon_menu = createApplicationMenu(scr);
  622.     free(scr->icon_menu->entries[1]->text);
  623.     }
  624.  
  625.     menu = scr->icon_menu;
  626.  
  627.     if (wapp->flags.hidden) {
  628.     menu->entries[1]->text = _("Unhide");
  629.     } else {
  630.     menu->entries[1]->text = _("Hide");
  631.     }
  632.  
  633.     menu->flags.realized = 0;
  634.     wMenuRealize(menu);
  635.  
  636.     x -= menu->frame->core->width/2;
  637.     if (x + menu->frame->core->width > scr->scr_width)
  638.     x = scr->scr_width - menu->frame->core->width;
  639.     if (x < 0)
  640.     x = 0;
  641.  
  642.     /* set client data */
  643.     for (i = 0; i < menu->entry_no; i++) {
  644.     menu->entries[i]->clientdata = wapp;
  645.     }
  646.     wMenuMapAt(menu, x, y, False);
  647. }
  648.  
  649.  
  650. /******************************************************************/
  651.  
  652. static void
  653. iconExpose(WObjDescriptor *desc, XEvent *event)
  654. {
  655.     wAppIconPaint(desc->parent);
  656. }
  657.  
  658.  
  659. static void
  660. iconDblClick(WObjDescriptor *desc, XEvent *event)
  661. {
  662.     WAppIcon *aicon = desc->parent;
  663.     WApplication *wapp;
  664.     WScreen *scr = aicon->icon->core->screen_ptr;
  665.     int unhideHere;
  666.  
  667. #ifndef REDUCE_APPICONS
  668.     assert(aicon->icon->owner!=NULL);
  669. #else
  670.     if (aicon->icon->owner == NULL) {
  671.        fprintf(stderr, "Double-click disabled: missing main window.\n");
  672.        return;
  673.     }
  674. #endif
  675.  
  676.     wapp = wApplicationOf(aicon->icon->owner->main_window);
  677. #ifdef DEBUG0
  678.     if (!wapp) {
  679.     wwarning("could not find application descriptor for app icon!!");
  680.     return;
  681.     }
  682. #endif
  683. #ifdef REDUCE_APPICONS
  684.     if (!wapp) {
  685.        fprintf(stderr, "Double-click disabled: missing wapp.\n");
  686.        return;
  687.     }
  688. #endif /* REDUCE_APPICONS */
  689.  
  690.     unhideHere = (event->xbutton.state & ShiftMask);
  691.  
  692.     /* go to the last workspace that the user worked on the app */
  693.     if (!unhideHere && wapp->last_workspace != scr->current_workspace)
  694.     wWorkspaceChange(scr, wapp->last_workspace);
  695.  
  696.     wUnhideApplication(wapp, event->xbutton.button==Button2, unhideHere);
  697.  
  698.     if (event->xbutton.state & MOD_MASK) {
  699.     wHideOtherApplications(aicon->icon->owner);
  700.     }
  701. }
  702.  
  703.  
  704. void
  705. appIconMouseDown(WObjDescriptor *desc, XEvent *event)
  706. {
  707.     WAppIcon *aicon = desc->parent;
  708.     WIcon *icon = aicon->icon;
  709.     XEvent ev;
  710.     int x=aicon->x_pos, y=aicon->y_pos;
  711.     int dx=event->xbutton.x, dy=event->xbutton.y;
  712.     int grabbed=0;
  713.     int done=0;
  714.     int superfluous = wPreferences.superfluous; /* we catch it to avoid problems */
  715.     WScreen *scr = icon->core->screen_ptr;
  716.     WWorkspace *workspace = scr->workspaces[scr->current_workspace];
  717.     int shad_x = 0, shad_y = 0, docking=0, dockable, collapsed = 0;
  718.     int ix, iy;
  719.     int clickButton = event->xbutton.button;
  720.     Pixmap ghost = None;
  721.     Window wins[2];
  722.  
  723.     if (aicon->editing || WCHECK_STATE(WSTATE_MODAL))
  724.     return;
  725.  
  726.     if (IsDoubleClick(scr, event)) {
  727.     iconDblClick(desc, event);
  728.     return;
  729.     }
  730.  
  731.     if (event->xbutton.button == Button3) {
  732.     WObjDescriptor *desc;
  733.     WApplication *wapp = wApplicationOf(aicon->icon->owner->main_window);
  734.  
  735.     if (!wapp)
  736.         return;
  737.  
  738.     if (event->xbutton.send_event &&
  739.         XGrabPointer(dpy, aicon->icon->core->window, True, ButtonMotionMask
  740.              |ButtonReleaseMask|ButtonPressMask, GrabModeAsync,
  741.              GrabModeAsync, None, None, CurrentTime) !=GrabSuccess) {
  742.         wwarning("pointer grab failed for appicon menu");
  743.         return;
  744.     }
  745.  
  746.     openApplicationMenu(wapp, event->xbutton.x_root,
  747.                 event->xbutton.y_root);
  748.  
  749.     /* allow drag select of menu */
  750.     desc = &scr->icon_menu->menu->descriptor;
  751.     event->xbutton.send_event = True;
  752.     (*desc->handle_mousedown)(desc, event);
  753.     return;
  754.     }
  755.  
  756. #ifdef DEBUG
  757.     puts("Moving icon");
  758. #endif
  759.     if (event->xbutton.state & MOD_MASK)
  760.     wLowerFrame(icon->core);
  761.     else
  762.     wRaiseFrame(icon->core);
  763.  
  764.  
  765.     if (XGrabPointer(dpy, icon->core->window, True, ButtonMotionMask
  766.              |ButtonReleaseMask|ButtonPressMask, GrabModeAsync,
  767.              GrabModeAsync, None, None, CurrentTime) !=GrabSuccess) {
  768.     wwarning("pointer grab failed for appicon move");
  769.     }
  770.  
  771.     if (wPreferences.flags.nodock && wPreferences.flags.noclip)
  772.       dockable = 0;
  773.     else
  774.       dockable = canBeDocked(icon->owner);
  775.  
  776.     wins[0] = icon->core->window;
  777.     wins[1] = scr->dock_shadow;
  778.     XRestackWindows(dpy, wins, 2);
  779.     if (superfluous) {
  780.         if (icon->pixmap!=None)
  781.             ghost = MakeGhostIcon(scr, icon->pixmap);
  782.         else
  783.             ghost = MakeGhostIcon(scr, icon->core->window);
  784.         XSetWindowBackgroundPixmap(dpy, scr->dock_shadow,
  785.                                    ghost);
  786.         XClearWindow(dpy, scr->dock_shadow);
  787.     }
  788.  
  789.     while (!done) {
  790.     WMMaskEvent(dpy, PointerMotionMask|ButtonReleaseMask|ButtonPressMask
  791.             |ButtonMotionMask|ExposureMask, &ev);
  792.     switch (ev.type) {
  793.      case Expose:
  794.         WMHandleEvent(&ev);
  795.         break;
  796.  
  797.      case MotionNotify:
  798.         if (!grabbed) {
  799.         if (abs(dx-ev.xmotion.x)>=MOVE_THRESHOLD
  800.             || abs(dy-ev.xmotion.y)>=MOVE_THRESHOLD) {
  801.             XChangeActivePointerGrab(dpy, ButtonMotionMask
  802.                         |ButtonReleaseMask|ButtonPressMask,
  803.                          wCursor[WCUR_MOVE], CurrentTime);
  804.             grabbed=1;
  805.         } else {
  806.             break;
  807.         }
  808.         }
  809.         x = ev.xmotion.x_root - dx;
  810.         y = ev.xmotion.y_root - dy;
  811.         XMoveWindow(dpy, icon->core->window, x, y);
  812.  
  813.         if (dockable) {
  814.                 if (scr->dock && wDockSnapIcon(scr->dock, aicon, x, y,
  815.                                                &ix, &iy, False)) {
  816.                     shad_x = scr->dock->x_pos + ix*wPreferences.icon_size;
  817.             shad_y = scr->dock->y_pos + iy*wPreferences.icon_size;
  818.  
  819.                     if (scr->last_dock != scr->dock && collapsed) {
  820.                         scr->last_dock->collapsed = 1;
  821.                         wDockHideIcons(scr->last_dock);
  822.                         collapsed = 0;
  823.                     }
  824.                     if (!collapsed && (collapsed = scr->dock->collapsed)) {
  825.                         scr->dock->collapsed = 0;
  826.                         wDockShowIcons(scr->dock);
  827.                     }
  828.  
  829.                     if (scr->dock->auto_raise_lower)
  830.                         wDockRaise(scr->dock);
  831.  
  832.                     scr->last_dock = scr->dock;
  833.  
  834.             XMoveWindow(dpy, scr->dock_shadow, shad_x, shad_y);
  835.             if (!docking) {
  836.                         XMapWindow(dpy, scr->dock_shadow);
  837.             }
  838.             docking = 1;
  839.                 } else if (workspace->clip &&
  840.                            wDockSnapIcon(workspace->clip, aicon, x, y,
  841.                                          &ix, &iy, False)) {
  842.                     shad_x = workspace->clip->x_pos + ix*wPreferences.icon_size;
  843.             shad_y = workspace->clip->y_pos + iy*wPreferences.icon_size;
  844.  
  845.                     if (scr->last_dock != workspace->clip && collapsed) {
  846.                         scr->last_dock->collapsed = 1;
  847.                         wDockHideIcons(scr->last_dock);
  848.                         collapsed = 0;
  849.                     }
  850.                     if (!collapsed && (collapsed = workspace->clip->collapsed)) {
  851.                         workspace->clip->collapsed = 0;
  852.                         wDockShowIcons(workspace->clip);
  853.                     }
  854.  
  855.                     if (workspace->clip->auto_raise_lower)
  856.                         wDockRaise(workspace->clip);
  857.  
  858.                     scr->last_dock = workspace->clip;
  859.  
  860.             XMoveWindow(dpy, scr->dock_shadow, shad_x, shad_y);
  861.             if (!docking) {
  862.             XMapWindow(dpy, scr->dock_shadow);
  863.             }
  864.                     docking = 1;
  865.         } else if (docking) {
  866.             XUnmapWindow(dpy, scr->dock_shadow);
  867.                     docking = 0;
  868.         }
  869.             }
  870.  
  871.         break;
  872.  
  873.      case ButtonPress:
  874.         break;
  875.  
  876.      case ButtonRelease:
  877.         if (ev.xbutton.button != clickButton)
  878.         break;
  879.         XUngrabPointer(dpy, CurrentTime);
  880.  
  881.             if (docking) {
  882.         Bool docked;
  883.  
  884.         /* icon is trying to be docked */
  885.         SlideWindow(icon->core->window, x, y, shad_x, shad_y);
  886.         XUnmapWindow(dpy, scr->dock_shadow);
  887.                 docked = wDockAttachIcon(scr->last_dock, aicon, ix, iy);
  888.                 if (scr->last_dock->auto_collapse) {
  889.                     collapsed = 0;
  890.                 }
  891.                 if (workspace->clip &&
  892.                     workspace->clip != scr->last_dock &&
  893.                     workspace->clip->auto_raise_lower)
  894.                     wDockLower(workspace->clip);
  895.  
  896.         if (!docked) {
  897.             /* If icon could not be docked, slide it back to the old
  898.              * position */
  899.             SlideWindow(icon->core->window, x, y, aicon->x_pos,
  900.                 aicon->y_pos);
  901.         }
  902.  
  903. #ifdef WMSOUND
  904.         wSoundPlay(WMSOUND_DOCK);
  905. #endif
  906.             } else {
  907.         XMoveWindow(dpy, icon->core->window, x, y);
  908.         aicon->x_pos = x;
  909.         aicon->y_pos = y;
  910.                 if (workspace->clip && workspace->clip->auto_raise_lower)
  911.                     wDockLower(workspace->clip);
  912.             }
  913.         if (collapsed) {
  914.         scr->last_dock->collapsed = 1;
  915.         wDockHideIcons(scr->last_dock);
  916.         collapsed = 0;
  917.         }
  918.         if (superfluous) {
  919.         if (ghost!=None)
  920.             XFreePixmap(dpy, ghost);
  921.         XSetWindowBackground(dpy, scr->dock_shadow, scr->white_pixel);
  922.         }
  923.  
  924.         if (wPreferences.auto_arrange_icons)
  925.         wArrangeIcons(scr, True);
  926.  
  927.         done = 1;
  928.         break;
  929.     }
  930.     }
  931. #ifdef DEBUG
  932.     puts("End icon move");
  933. #endif
  934.  
  935. }
  936.